import time
from threading import Event
import re
from ...utils.workflow_manager import WorkFlow
from ...utils.utils import singleton
from ...utils.loggers import dev_logger, record_logger
import tkinter as tk


@singleton
class HotWorkFlow(WorkFlow):
    step0_flag = False
    step6_flag = False
    step7_flag = False
    # 每2s发送一次诊断报文的信号
    step1_cycle_event = Event()
    step2_cycle_event = Event()
    step1_cycle_flag = False
    step2_cycle_flag = False
    step5TimeLeft = 6
    unit_debug = False
    VIN_ENABLE_HOT = False
    NOT_HOT_CONFIRM = True

    def sendMsg_checkRecv(self, sendId=None, sendData=None, recvId=None, recvData=None, delay=0.5, tryCounts=5):
        def clearBuffer():
            # 清空buffer1的缓存，从按下加热指令开始接收数据
            self.mainView.clearBuffer1()
            # 清空接收的queue
            self.mainView.recvMsgDeque.clear()

        def sendMsg():
            if sendId is not None and sendData is not None:
                self.mainView.sendcan1_manual(sendId, sendData)
            else:
                raise 'no sendId or no sendData'

        # 初次发送前清理Buffer
        clearBuffer()

        while tryCounts > 0:
            tryCounts -= 1
            while len(self.mainView.recvMsgDeque) > 0:
                curMsg = self.mainView.recvMsgDeque.popleft()
                # curMsg[0],原本是字符串16进制格式，通过int转换为数字格式，后面与recvId对比时候就不报错了
                curId = int(curMsg[0], 16)
                curData = curMsg[1]
                dev_logger.debug(f'curId:{hex(curId)},curData:{curData}')
                # [ ]: 后续只要比较前6为即可，后面的10位不做比较
                if curId == recvId and curData == recvData:
                    # 一旦检查到预期反馈信号，程序结束并返回结果
                    return True

                if curId == 0x5e0:
                    def boli_penzui_jiare_handle(data):
                        # 共8个字，第3个字是加热的字
                        tempStatus = int(data[4:6], 16)
                        # 第五位是加热状态位
                        and01 = tempStatus & 0b00010000
                        # 返回加热状态位,第五位如果是1就结果是16，第五位如果是0，结果就是0
                        return and01

                    print('recvData:', type(recvData), recvData)
                    print('curData:', type(curData), curData)
                    print('jiagong(recvData):',
                          boli_penzui_jiare_handle(recvData))
                    print('jiagong(curData):', boli_penzui_jiare_handle(curData))
                    if boli_penzui_jiare_handle(recvData) == boli_penzui_jiare_handle(curData):
                        return True

            # FIXME: 上面的while只要没有走到break，哪怕是因为初始条件不满足，就会走到else分支里
            else:
                # 先发信号
                sendMsg()
                # 等待一段时间,与上一条顺序不能错了
                time.sleep(delay)
                # 如果程序走到此处，说明没有匹配成功，直接进行下一个tryCounts大循环，避免走到下面的break
                continue

        # 如果整车结束，说明一直没有接收到预期反馈信号
        dev_logger.debug(f'发送{hex(sendId)}:{sendData}信息，未收到预期反馈{
                         hex(recvId)}:{recvData},请检查原因')
        return False

    def display_log(self, log):
        self.mainView.userWindowFrame6recordListbox_2.insert(tk.END, log)
        self.mainView.userWindowFrame6recordListbox_2.see(tk.END)

    def display_warning(self, warning):
        self.display_log(warning)
        self.mainView.userWindowFrame6recordListbox_2.itemconfig(
            'end', background='pink')

    def display_record(self, msg):
        record_logger.info(msg)

    def refreshMainViewStep(self):
        # print('refreshMainViewStep')
        # FIXME: 此处是否要用多线程？把workflow的run放到新开的线程里(因run含有while True循环)，这里就不用在开多线程了
        self.mainView.refreshStep(self.getStep())

    def vinStep0Get(self):

        # vin validate
        def validateVinCode(curVin):
            # TODO: 待开启VIN匹配功能
            pat = re.compile(r'^LNB\w{8}\d{6}$')
            if pat.match(curVin):
                # if len(curVin) > 4:
                return True
            else:
                return False
        readVin = self.mainView.curVinCode.get()
        if validateVinCode(readVin):
            self.curVin = readVin
            self.display_log(f'curVin:{readVin}')
            return True
        else:
            self.display_warning(f'当前输入的vin是：{readVin},格式有误，请检查确认')
            return False

    def vinStep7Reset(self):
        self.mainView.curVinCode.set('')

    def setEvent(self):
        # 重置event，跳出子线程循环
        self.step1_cycle_event.set()
        self.step2_cycle_event.set()

    def stepReset(self):
        self.setEvent()
        self.setStep(0)

    def step0SetFlag(self):
        if self.VIN_ENABLE_HOT:
            if self.vinStep0Get():
                self.step0BtnDisable()
                self.step0_flag = True
            else:
                self.display_log('获取Vin出现异常...')
        else:
            self.step0BtnDisable()
            self.step0_flag = True

    def step0ResetFlag(self):
        self.step0BtnEnable()
        self.step0_flag = False

    def step0BtnEnable(self):
        self.mainView.userWindowFrame3StepsFrameStep0Frm_btn1.configure(
            state='normal')

    def step0BtnDisable(self):
        self.mainView.userWindowFrame3StepsFrameStep0Frm_btn1.configure(
            state='disabled')

    def handleStep0(self):
        # [x]: 等待启动检测，默认直接启动，就进入到step0状态中
        if not self.step0_flag:
            # self.step0_flag 的设置在UI上用按钮触发
            dev_logger.debug('handleStep0，等待启动检测')
            self.display_log('Step0，等待启动检测, 请确认点击启动检测按钮')
        else:
            self.nextStep()

    def step1_loop_2s_event(self):
        while True:
            time.sleep(2)
            # 如果Event被set了，就退出循环
            if self.step1_cycle_event.is_set():
                # [ ]: 此处做一些收尾清理工作
                # step1_cycle_flag = False，因为下一次还要用
                self.step1_cycle_flag = False
                # 清除event，因为下一次还要用
                # event.clear()
                self.step1_cycle_event.clear()
                break
            if not self.unit_debug:
                self.mainView.sendcan1_manual(0x723, "023E000000000000")
            dev_logger.debug('每间隔2s发送诊断信号----0x723:02 3E 00 00 00 00 00 00')

    def handleStep1(self):
        # 步数完成信号
        stepOverFlag = False
        # [x]: 给空调控制器发停发报文的指令，诊断服务，1003-2803
        # print(self.mainView.sendcan1_manual(0x723, "021003cccccccccc"))
        # print(self.mainView.sendcan1_manual)

        dev_logger.debug('handlerStep1--给空调控制器发停发报文指令，诊断服务，1003-2803')
        self.display_log('Step1，给空调控制器发停发报文指令，诊断服务，1003-2803')

        if not self.unit_debug:
            self.mainView.sendcan1_manual(0x723, '0210030000000000')
        dev_logger.debug('0x723:02 10 03 00 00 00 00 00')

        # [x]: 每2s一次的诊断信号停止,在step7 通过设定event线程通讯实现
        if not self.step1_cycle_flag:
            # 如果没有开启循环，创建线程和Event开启循环
            self.pool.submit(self.step1_loop_2s_event)
            # 只开启一次循环，直到循环被event.set()，在那里会把self.step1_cycle_flag = False，就可以重新开启循环
            self.step1_cycle_flag = True

        # 发送2803信号
        dev_logger.debug('0x723:03 28 03 01 00 00 00 00')
        if not self.unit_debug:
            if self.sendMsg_checkRecv(sendId=0x723, sendData='0328030100000000', recvId=0x7a3, recvData='026803aaaaaaaaaa'):
                # 固定格式
                stepOverFlag = True
            else:
                self.display_warning('step1，发送[0x732:0328030100000000]未成功')
        else:
            stepOverFlag = True

        # 进入下一步判断
        if stepOverFlag:
            self.nextStep()

    def step2_loop_event(self):
        while True:
            time.sleep(1)
            # 如果Event被set了，就退出循环
            if self.step2_cycle_event.is_set():
                # [ ]: 此处做一些收尾清理工作
                # step1_cycle_flag = False，因为下一次还要用
                self.step2_cycle_flag = False
                # 清除event，因为下一次还要用
                # event.clear()
                self.step2_cycle_event.clear()
                break
            if not self.unit_debug:
                self.mainView.sendcan1_manual(0x530, "0000182000000000")
            dev_logger.debug('每间隔1s发送温度信号----0x530:00 00 18 20 00 00 00 00')

    def handleStep2(self):
        stepOverFlag = False
        # [x]: 给BDC发温度信号(ID:0x530,data:00 00 18 20 00 00 00 00)
        dev_logger.debug('handleStep2--给BDC发温度信号')
        self.display_log('Step2，给BDC发温度信号')

        dev_logger.debug('ID:0x530,data:00 00 18 20 00 00 00 00')
        # print(self.mainView.sendcan1_manual(0x530, "0000182000000000"))

        # [x]: 信号停止,在step7 通过设定event线程通讯实现
        if not self.step2_cycle_flag:
            # 如果没有开启循环，创建线程和Event开启循环
            self.pool.submit(self.step2_loop_event)
            # 只开启一次循环，直到循环被event.set()，在那里会把self.step1_cycle_flag = False，就可以重新开启循环
            self.step2_cycle_flag = True

        stepOverFlag = True

        if stepOverFlag:
            self.nextStep()

    def step3_boliJiareLabelSet(self):
        self.mainView.userWindowFrame3StepsFrameStep3Frm_boliJiareLabel.configure(
            text='加热中...', foreground='green', font=('Arial', 32))

    def step3_boliJiareLabelReset(self):
        self.mainView.userWindowFrame3StepsFrameStep3Frm_boliJiareLabel.configure(
            text='未加热...', foreground='gray')

    def handleStep3(self):
        stepOverFlag = False

        # [x]: 通过空调屏给开关，给玻璃发出加热指令,改为指令发送
        # [ ]: 0x512,0000002000000000 待确认信号
        self.display_log('Step3，通过空调屏给开关，给玻璃发出加热指令')

        if not self.unit_debug:
            if self.sendMsg_checkRecv(sendId=0x512, sendData='0000002000000000', recvId=0x5e0, recvData='6080b00000000000'):
                # if self.sendMsg_checkRecv(sendId=0x512, sendData='0000002000000000', recvId=0x5e0, recvData= '60c0490100000000'):
                dev_logger.debug('玻璃加热开启成功...')
                self.step3_boliJiareLabelSet()
                # 下一步条件满足
                stepOverFlag = True
            else:
                self.display_warning('step3，发送[0x512:0000002000000000]未成功')
        else:
            stepOverFlag = True

        # stepOverFlag = True
        if stepOverFlag:
            self.nextStep()

    def handleStep4(self):
        stepOverFlag = False

        # [x]: 通过空调屏给开关，给喷嘴发出加热指令,改为指令控制
        # 与第三步的信号是相同的
        self.display_log('Step4，通过空调屏给开关，给喷嘴发出加热指令')

        stepOverFlag = True
        if stepOverFlag:
            self.nextStep()

    def handleStep5(self):
        stepOverFlag = False
        # [ ]: 延时1分钟，提示作业者可以用手触摸加热效果
        dev_logger.debug('handleStep5---延时1分钟，提示作业者可以确认加热效果')
        self.display_log('Step5，延时1分钟，提示作业者可以确认加热效果')
        loopTime = self.step5TimeLeft
        while (loopTime > 0):
            # 间隔提醒时间
            delta = 1
            time.sleep(delta)
            loopTime -= delta
            dev_logger.debug(f'加热等待剩余时间：{loopTime} 秒')
            self.mainView.userWindowFrame3StepsFrameStep5Frm_label2.configure(
                text=loopTime)
            if loopTime == 0:
                self.mainView.userWindowFrame3StepsFrameStep5Frm_label2.configure(
                    text="**")

        # 延时时间到达后，可以进入下一步
        stepOverFlag = True
        if stepOverFlag:
            # 打开step6 按钮使能
            self.step6BtnEnable()
            self.nextStep()

    def step6BtnEnable(self):
        self.mainView.userWindowFrame3StepsFrameStep6Frm_btn1.configure(
            state='normal')

    def step6BtnDisable(self):
        self.mainView.userWindowFrame3StepsFrameStep6Frm_btn1.configure(
            state='disabled')

    def step6SetFlag(self):
        # 确认加热效果后，就可以停止加热了
        self.step3_boliJiareLabelReset()
        self.step6BtnDisable()
        self.step6_flag = True

    def step6ResetFlag(self):
        self.step6_flag = False

    def handleStep6(self):
        stepOverFlag = False
        # [x]: 判断是否变热，输入按钮反馈，改变stepOverFlag的状态
        # [x]: 作业者触摸后反馈正常,按对应的按钮

        # [ ]: 此处还要增加反馈异常的处理逻辑
        dev_logger.debug("handleStep6---待确认加热效果是否正常")
        self.display_log('Step6，待确认加热效果是否正常')

        # 如果设置了不需要确认加热效果，就自动触发按钮，不需要人手点击，这样如果启动确认，只要设置NOT_HOT_CONFIRM为False即可
        if self.NOT_HOT_CONFIRM:
            self.step6SetFlag()

        # [ ]: 作业者触摸后反馈正常,按对应的按钮
        if self.step6_flag:
            stepOverFlag = True

        # 如果NOT_HOT_CONFIRM为True，就不需要等待作业者确认加热效果，直通下个步数
        if stepOverFlag:
            self.nextStep()

    def step7SetFlag(self):
        # print("setStep7Flag running....")
        self.step7_flag = True
        # print("setStep7Flag running....")
        self.setEvent()

    def step7ResetFlag(self):
        self.step7_flag = False

    def handleStep7(self):
        # FIXME: 不能在此处设置，否则外面对self.step7_flag的设置会被覆盖
        # self.step7_flag = False
        dev_logger.debug("handleStep7 running.......")

        dev_logger.debug('每间隔2s发送诊断信号停发')

        # 增加no_confirm选项
        if not self.unit_debug and not self.NO_CONFIRM:
            if self.sendMsg_checkRecv(0x512,  '0000002000000000', 0x5e0, '6080280000000000'):
                dev_logger.debug('玻璃加热停止成功...')
                self.step7SetFlag()
            else:
                self.display_warning('step7，发送[0x512:0000002000000000]未成功')
        else:
            self.step7SetFlag()

        if self.step7_flag:
            # 记录测试日志
            if self.VIN_ENABLE_HOT:
                self.display_record(f'VIN,{self.curVin},检测完成')
            self.display_log('Step7，检测正常，结束本台车加热检测...')

            # [ ]: 后续复位可以与动作关联
            # 复位step0，下一次循环需要再次置位
            self.step0ResetFlag()
            self.step6ResetFlag()
            if self.VIN_ENABLE_HOT:
                self.vinStep7Reset()

            #  恢复正常发送报文
            if not self.unit_debug:
                self.mainView.sendcan1_manual(0x723, '0328000100000000')
            dev_logger.debug('0x723:03 28 00 01 00 00 00 00')

            # 重置step7_flag，该信号要在if之中设置，否则如果在外面set会导致永远进不来if条件
            self.step7ResetFlag()

            # print("step7_flag true  ....")
            self.nextStep()
